package com.sk.rpcAssistNetty.io.netty.server;

import com.alibaba.fastjson.serializer.JSONSerializer;
import com.sk.rpcAssistNetty.io.netty.RpcRequest;
import com.sk.rpcAssistNetty.io.netty.RpcResponse;
import com.sk.rpcAssistNetty.io.netty.codec.RpcDecoder;
import com.sk.rpcAssistNetty.io.netty.codec.RpcEncoder;
import com.sk.rpcAssistNetty.io.protocol.ProtocolManage;
import com.sk.rpcAssistNetty.io.protocol.SerializeProtocol;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;

/**
 * description：
 *
 * @author 孙文斌
 * @Date: 2021/3/18 10:29
 */
@Slf4j
public class NettyServer {

    private Integer port;
    private SerializeProtocol serializeProtocol;

    public NettyServer(Integer port, SerializeProtocol serializeProtocol) {
        this.port = port;
        this.serializeProtocol = serializeProtocol;
    }

    public void doStart() throws Exception {
        initNettyServer();
    }

    public void initNettyServer() throws Exception {

        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)//标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1
                .option(ChannelOption.TCP_NODELAY, true)//禁止nagle算法，客户端和服务端需同时设置
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
//                        pipeline.addLast(new LengthFieldBasedFrameDecoder(65535, 0, 4));
                        pipeline.addLast(new RpcDecoder(RpcRequest.class, serializeProtocol));
                        pipeline.addLast(new RpcEncoder(RpcResponse.class, serializeProtocol));
                        pipeline.addLast(new ServerHandler());

                    }
                });
        bind0(serverBootstrap, this.port);

        //创建Bossgroup和workerGroup
//        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
//        try {
//            //创建服务端启动对象，配置参数
//            ServerBootstrap bootstrap = new ServerBootstrap();
//            bootstrap.group(bossGroup, workerGroup)//设置两个线程组
//                    .channel(NioServerSocketChannel.class)//使用NNioServerSocketChannel作为服务器的通道实现
//                    .option(ChannelOption.SO_BACKLOG, 1024)//设置线程队列得到连接个数
//                    .childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接状态
//                    .childHandler(new ChannelInitializer<SocketChannel>() {//给workerGroup对应的EventLoop对应的管道设置处理器
//                        protected void initChannel(SocketChannel socketChannel) throws Exception {
//                            socketChannel.pipeline().addLast(new RpcDecoder(RpcRequest.class, serializeProtocol));
//                            socketChannel.pipeline().addLast(new RpcEncoder(RpcResponse.class, serializeProtocol));
//                            socketChannel.pipeline().addLast(new ServerHandler());//给管道pipeline设置处理器
//                        }
//                    });
//            //启动服务器,绑定端口
////            bind(bootstrap, port);
//            ChannelFuture future = bootstrap.bind(23333).sync();
//            System.out.println("服务端已启动！");
//            //对关闭通道进行监听
////            future.channel().closeFuture().sync();
//        } finally {
//
//            //优雅的关闭
////            System.out.println("关闭了");
//            //todo：在主线程未阻塞的情况下关闭LoopGroup导致不能接受客户端请求
////            bossGroup.shutdownGracefully();
////            workerGroup.shutdownGracefully();
//        }
    }
    /**
     * 如果端口绑定失败，端口数+1,重新绑定
     *
     * @param serverBootstrap
     * @param port
     */
    public void bind0(final ServerBootstrap serverBootstrap,int port) {
        serverBootstrap.bind(port).addListener(future -> {
            if (future.isSuccess()) {
                log.info("端口[ {} ] 绑定成功",port);
            } else {
                log.error("端口[ {} ] 绑定失败", port);
                bind0(serverBootstrap, port + 1);
            }
        });
    }
}
